import React, { useState, useContext, useRef, useEffect } from 'react'
import Tabs, { TabPane } from 'rc-tabs'
// @ts-ignore
import { history } from 'dumi'
import type { IPreviewerComponentProps } from 'dumi/theme'
import {
  context,
  useCodeSandbox,
  useRiddle,
  useMotions,
  useCopy,
  useLocaleProps,
  useDemoUrl,
  useTSPlaygroundUrl,
  Link,
  AnchorLink,
  usePrefersColor,
} from 'dumi/theme'
import type { ICodeBlockProps } from './SourceCode'
import SourceCode from './SourceCode'
import './Previewer.less'

export interface IPreviewerProps extends IPreviewerComponentProps {
  /**
   * enable transform to change CSS containing block for demo
   */
  transform?: boolean
  /**
   * modify background for demo area
   */
  background?: string
  /**
   * collapse padding of demo area
   */
  compact?: boolean
  /**
   * configurations for action button
   */
  hideActions?: ('CSB' | 'EXTERNAL' | 'RIDDLE')[]
  /**
   * show source code by default
   */
  defaultShowCode?: boolean
  /**
   * use iframe mode for this demo
   */
  iframe?: true | number
  /**
   * replace builtin demo url
   */
  demoUrl?: string
}

/**
 * get source code type for file
 * @param file    file path
 * @param source  file source object
 */
function getSourceType(
  file: string,
  source: IPreviewerComponentProps['sources']['_'],
) {
  // use file extension as source type first
  let type = file.match(/\.(\w+)$/)?.[1]

  if (!type) {
    type = source.tsx ? 'tsx' : 'jsx'
  }

  return type as ICodeBlockProps['lang']
}

const Previewer: React.FC<IPreviewerProps> = oProps => {
  const demoRef = useRef()
  const { locale } = useContext(context)
  const props = useLocaleProps<IPreviewerProps>(locale, oProps)
  const builtinDemoUrl = useDemoUrl(props.identifier)
  const demoUrl = props.demoUrl || builtinDemoUrl
  const isActive = history?.location.hash === `#${props.identifier}`
  const isSingleFile = Object.keys(props.sources).length === 1
  const openCSB = useCodeSandbox(
    props.hideActions?.includes('CSB') ? null : props,
  )
  const openRiddle = useRiddle(
    props.hideActions?.includes('RIDDLE') ? null : props,
  )
  const [execMotions, isMotionRunning] = useMotions(
    props.motions || [],
    demoRef.current,
  )
  const [copyCode, copyStatus] = useCopy()
  const [currentFile, setCurrentFile] = useState(() =>
    props.sources._ ? '_' : Object.keys(props.sources)[0],
  )
  const [sourceType, setSourceType] = useState(
    getSourceType(currentFile, props.sources[currentFile]),
  )
  const [showSource, setShowSource] = useState(
    typeof props.defaultShowCode === 'undefined'
      ? true
      : Boolean(props.defaultShowCode),
  )
  const [iframeKey, setIframeKey] = useState(Math.random())
  const currentFileCode =
    props.sources[currentFile][sourceType] || props.sources[currentFile].content
  const playgroundUrl = useTSPlaygroundUrl(locale, currentFileCode)
  const iframeRef = useRef<HTMLIFrameElement>()
  const [color] = usePrefersColor()

  // re-render iframe if prefers color changed
  useEffect(() => {
    setIframeKey(Math.random())
  }, [color])

  function handleFileChange(filename: string) {
    setCurrentFile(filename)
    setSourceType(getSourceType(filename, props.sources[filename]))
  }

  props.iframe = true

  return (
    <div
      style={props.style}
      className={[
        props.className,
        '__dumi-default-previewer',
        isActive ? '__dumi-default-previewer-target' : '',
      ]
        .filter(Boolean)
        .join(' ')}
      id={props.identifier}
      data-debug={props.debug || undefined}
      data-iframe={props.iframe || undefined}>
      <div className="__dumi-default-previewer-code-ctx">
        <div className="__dumi-default-previewer-desc" data-title={props.title}>
          {props.title && (
            <AnchorLink to={`#${props.identifier}`}>{props.title}</AnchorLink>
          )}
          {props.description && (
            <div
              // eslint-disable-next-line
              dangerouslySetInnerHTML={{ __html: props.description }}
            />
          )}
        </div>
        <div className="__dumi-default-previewer-actions">
          {openCSB && (
            <button
              title="Open demo on CodeSandbox.io"
              className="__dumi-default-icon"
              role="codesandbox"
              onClick={openCSB}
            />
          )}
          {openRiddle && (
            <button
              title="Open demo on Riddle"
              className="__dumi-default-icon"
              role="riddle"
              onClick={openRiddle}
            />
          )}
          {props.motions && (
            <button
              title="Execute motions"
              className="__dumi-default-icon"
              role="motions"
              disabled={isMotionRunning}
              onClick={() => execMotions()}
            />
          )}
          {props.iframe && (
            <button
              title="Reload demo iframe page"
              className="__dumi-default-icon"
              role="refresh"
              onClick={() => setIframeKey(Math.random())}
            />
          )}
          {!props.hideActions?.includes('EXTERNAL') && (
            <Link target="_blank" to={demoUrl}>
              <button
                title="Open demo in new tab"
                className="__dumi-default-icon"
                role="open-demo"
                type="button"
              />
            </Link>
          )}
          <span />
          <button
            title="Copy source code"
            className="__dumi-default-icon"
            role="copy"
            data-status={copyStatus}
            onClick={() => copyCode(currentFileCode)}
          />
          {sourceType === 'tsx' && showSource && (
            <Link target="_blank" to={playgroundUrl}>
              <button
                title="Get JSX via TypeScript Playground"
                className="__dumi-default-icon"
                role="change-tsx"
                type="button"
              />
            </Link>
          )}
          <button
            title="Toggle source code panel"
            className={`__dumi-default-icon${
              showSource ? ' __dumi-default-btn-expand' : ''
            }`}
            role="source"
            type="button"
            onClick={() => setShowSource(!showSource)}
          />
        </div>
        {showSource && (
          <div className="__dumi-default-previewer-source-wrapper">
            {!isSingleFile && (
              <Tabs
                className="__dumi-default-previewer-source-tab"
                prefixCls="__dumi-default-tabs"
                moreIcon="···"
                defaultActiveKey={currentFile}
                onChange={handleFileChange}>
                {Object.keys(props.sources).map(filename => (
                  <TabPane
                    tab={
                      filename === '_'
                        ? `index.${getSourceType(
                            filename,
                            props.sources[filename],
                          )}`
                        : filename
                    }
                    key={filename}
                  />
                ))}
              </Tabs>
            )}
            <div className="__dumi-default-previewer-source">
              <SourceCode
                code={currentFileCode}
                lang={sourceType}
                showCopy={false}
              />
            </div>
          </div>
        )}
      </div>

      {/* {props.iframe && (
          <div className="__dumi-default-previewer-browser-nav" />
        )} */}
      <div
        ref={demoRef}
        className="__dumi-default-previewer-demo"
        style={{
          transform: props.transform ? 'translate(0, 0)' : undefined,
          // padding:
          //   props.compact || (props.iframe && props.compact !== false)
          //     ? '0'
          //     : undefined,
          background: props.background,
        }}>
        {props.iframe ? (
          <iframe
            title="dumi-previewer"
            style={{
              // both compatible with unit or non-unit, such as 100, 100px, 100vh
              height: String(props.iframe).replace(/(\d)$/, '$1px'),
            }}
            key={iframeKey}
            src={demoUrl}
            ref={iframeRef}
          />
        ) : (
          props.children
        )}
      </div>
    </div>
  )
}

export default Previewer
